﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;

namespace Atosenet.Utility
{
    public class XmlQueryInterpreter
    {
        #region 成员

        

        #endregion


        #region 初始化

        public XmlQueryInterpreter()
        {
            ResultCollection = new List<QueryResult>();
        }

        #endregion


        #region 公开函数

        public string GetResult()
        {
            string result;

            if (!GetXmlResult(ResultCollection.ToArray(), out result))
            {
                GetXmlResult(QueryResult.CreateErrorResult(result), out result);
            }
            return result;
        }

        public string GetErrorResult(string msg)
        {
            string result;
            GetXmlResult(QueryResult.CreateErrorResult(msg), out result);
            return result;
        }

        public string GetBooleanResult(bool value, string msg)
        {
            string result;
            GetXmlResult(QueryResult.CreateBooleanResult(value, msg), out result);
            return result;
        }

        public void AddRecord(QueryResult result)
        {
            if (result != null)
                this.ResultCollection.Add(result);
        }

        #endregion


        #region 核心函数

        private bool GetXmlResult(QueryResult result, out string resultStr)
        {
            return GetXmlResult(new QueryResult[] { result }, out resultStr);
        }

        private bool GetXmlResult(QueryResult[] results, out string resultStr)
        {
            try
            {
                XmlDocument xmldoc = new XmlDocument();
                XmlDeclaration declare = xmldoc.CreateXmlDeclaration("1.0", "utf-8", null);
                XmlNode roots = xmldoc.CreateNode(XmlNodeType.Element, "results", null); 

                for (int i = 0; i < results.Length; i++)
                {
                    XmlNode root = xmldoc.CreateNode(XmlNodeType.Element, "result", null);
                    root.Attributes.Append(xmldoc.CreateAttribute("count")).InnerText = results[i].DataRows.Count.ToString();
                    root.Attributes.Append(xmldoc.CreateAttribute("message")).InnerText = results[i].Message;

                    for (int j = 0; j < results[i].DataRows.Count; j++)
                    {
                        XmlNode row = xmldoc.CreateNode(XmlNodeType.Element, "row", null);

                        for (int k = 0; k < results[i].DataRows[j].FieldValuePairs.Count; k++)
                        {
                            row.Attributes.Append(xmldoc.CreateAttribute(results[i].DataRows[j].FieldValuePairs[k].FieldName)).InnerText = results[i].DataRows[j].FieldValuePairs[k].Value;
                        }
                        root.AppendChild(row);
                    }
                    roots.AppendChild(root);
                }
                xmldoc.AppendChild(roots);
                xmldoc.InsertBefore(declare, xmldoc.DocumentElement);
                resultStr = GetStringFromXmlDoc(xmldoc);
                return true;
            }
            catch (Exception e)
            {
                resultStr = e.Message;
                return false;
            }
        }

        private string GetStringFromXmlDoc(XmlDocument xmldoc)
        {
            if (xmldoc == null)
                return string.Empty;

            string result = string.Empty;
            MemoryStream ms = new MemoryStream();
            xmldoc.Save(ms);

            using (StreamReader sr = new StreamReader(ms, Encoding.UTF8))
            {
                ms.Position = 0;
                result = sr.ReadToEnd();
                sr.Close();
                ms.Close();
            }
            return result;
        }

        #endregion


        #region 属性

        public List<QueryResult> ResultCollection
        {
            get;
            set;
        }

        #endregion


        #region 附加对象

        public class QueryResult
        {
            public QueryResult()
                : this(string.Empty)
            { }
 
            public QueryResult(string msg)
            {
                Message = msg;
                DataRows = new List<QueryRow>();
            }

            public void AddRecord(QueryRow row)
            {
                DataRows.Add(row);
            }

            public void AddRecord(FieldValuePair[] dataPairs)
            {
                DataRows.Add(new QueryRow(dataPairs));
            }

            public List<QueryRow> DataRows
            {
                get;
                set;
            }

            public string Message
            {
                get;
                set;
            }

            public static QueryResult CreateBooleanResult(bool result, string message)
            {
                QueryResult qResult = new QueryResult(message);
                FieldValuePair data;
                data.FieldName = "result";
                data.Value = result ? "1" : "0";
                qResult.AddRecord(new QueryRow(new FieldValuePair[] { data }));
                return qResult;
            }

            public static QueryResult CreateResult(string resultMsg, string message)
            {
                QueryResult qResult = new QueryResult(message);
                FieldValuePair data;
                data.FieldName = "result";
                data.Value = resultMsg;
                qResult.AddRecord(new QueryRow(new FieldValuePair[] { data }));
                return qResult;
            }

            public static QueryResult CreateErrorResult(string errorMsg)
            {
                QueryResult qResult = new QueryResult(errorMsg);
                return qResult;
            }
        }

        public class QueryRow
        {
            public QueryRow()
            {
                FieldValuePairs = new List<FieldValuePair>();
            }

            public QueryRow(FieldValuePair[] dataPairs)
                : this()
            {
                FieldValuePairs.AddRange(dataPairs);
            }

            public void AddRecord(FieldValuePair pair)
            {
                FieldValuePairs.Add(pair);
            }

            public void AddRecord(string field, string value)
            {
                FieldValuePair pair;
                pair.FieldName = field;
                pair.Value = value;
                AddRecord(pair);
            }

            public List<FieldValuePair> FieldValuePairs
            {
                get;
                set;
            }
        }

        public struct FieldValuePair
        {
            public string FieldName;
            public string Value;
        }

        #endregion
    }
}
